package testjeu;

import java.util.Arrays;
import java.util.Hashtable;
import org.newdawn.slick.Color;
import org.newdawn.slick.Graphics;
import org.newdawn.slick.SlickException;
import org.newdawn.slick.SpriteSheet;
import org.newdawn.slick.Image;

/**
 * Gestionnaire des cartes d'actions que le joueur peut disposer sur la carte.
 * <br />Chaque objet correspond à une carte
 * 
 * @author YoTsumi
 * @see Constantes.Actions
 */
public class Carte extends Jeu implements Constantes {

    private Actions carte;               // Action de la carte
    private int nb;                      // Nbre de cartes restantes de ce type
    private int[] x; private int[] y;    // Coordonnées des cartes 
    
    private int xStart, yStart, nbStart; // Pour Reset 
    private int index=0;                 // Index en cours
    private boolean[] indexPlacés;       // Les index entre 0 et NB des cartes, true si affectés ( = placés )
    private Image[] sprite;              // Les sprites (identiques) des cartes
    
    private boolean déplacement;         // Vrai si la carte est en cours de déplacement
    private boolean déplacementAutorisé; // Vrai si la case survolée pdt le déplacement autorise la pose d'une caete
    
    private int surlignage=-1;           // Index de la carte surlignée, -1 si aucune
     
    
    // Variables partagées entre toutes les occurences de Carte
    static Hashtable<Actions,cases> RelationCarteTile=new Hashtable<Actions, cases>();
    static Hashtable<Actions,Integer> RelationNbCartes=new Hashtable<Actions,Integer>();
    
    static SpriteSheet spriteCartes;
    static int ligEnCours=1;
    static int colEnCours=1;
    
   

    
    /**
     * Cré une nouvelle carte en fonction de son Action et de son ID 
     * On définis les coordonnées d'origine de la carte dans l'interface en fonction du nombre de cartes déjà disposées.
     * @param c     L'action de la carte
     * @param nb    Le nombre d'occurences de cette carte
     */
    public Carte(Actions c, int nb) {
        this.carte=c;
        this.nb=nb; this.nbStart=nb;
        
        cases laCase=RelationCarteTile.get(c);
        
        sprite=new Image[nbStart];
        x=new int[nbStart]; y=new int[nbStart];
        indexPlacés=new boolean[nbStart]; Arrays.fill(indexPlacés, false);
        
        for (int i=0; i<nbStart;i++) {
            sprite[i]=spriteCartes.getSprite(laCase.X()-1, laCase.Y()-1);
            x[i]=xStart=34+54*(colEnCours-1);
            y[i]=yStart=263+88*(ligEnCours-1);
        }
        
        colEnCours++;
        if (colEnCours==5) { colEnCours=1; ligEnCours=2; }
    }
    
    
    /**
     * Dessine la carte soit dans sa position d'origine, soit durant son déplacement sur la map
     * @param g     Le context graphic
     */
    public void dessiner(Graphics g) {

     
        
        // Si la case est pointée aprés être posée, on la surligne
        if( !déplacement && surlignage!=-1 && (cases.pxlToCol(x[surlignage]+20)>0 && cases.pxlToCol(x[surlignage]+20)<=15 && cases.pxlToLig(y[surlignage]+20)>0 && cases.pxlToLig(surlignage+20)<=15)) {
            g.setColor(new Color(255,255,255,150));
            g.drawRect(cases.debutCaseX(x[surlignage]+20), cases.debutCaseY(y[surlignage]+20), 40, 40);
            
        // Surlignage à l'origine
        } else if (surlignage!=-1 && !déplacement) {
            g.setColor(new Color(43,58,55,255));
            g.drawRect(xStart, yStart-1, 40, 40);
        }
         
        // Si la case est en déplacement, on affiche un cadre de couleur
        if (déplacement) {
            if (cases.pxlToCol(x[index]+20)>0 && cases.pxlToCol(x[index]+20)<=15 && cases.pxlToLig(y[index]+20)>0 && cases.pxlToLig(y[index]+20)<=15) {
                if (déplacementAutorisé) g.setColor(Color.yellow);
                else                     g.setColor(Color.red);
                g.drawRect(cases.debutCaseX(x[index]+20), cases.debutCaseY(y[index]+20), 40, 40);
            }
        }
        
        // On Affiche le nbre de carte disponibles
        for (int i=0; i<nbStart;i++) {
            sprite[i].draw(x[i], y[i]);
            g.setColor(Color.white);
            if (nb>0) g.drawString(Integer.toString(nb), xStart+28, yStart+42);
        }


    }
    
    /**
     * Vérifie si les coordonnées x,y pointent la carte dans son emplacement d'origine
     * @param x     Coordonnées x de la souris
     * @param y     Coordonnée y de la souris
     * @return      Vrai si (x,y) pointe la carte
     */
    public boolean estPointéOrigine(int x, int y) {
        return (x>=xStart && x<=xStart+40 && y>=yStart && y<=yStart+40 && nbIndexAffectés()<nbStart && !déplacement);
    }
    
    /**
     * Vérifie si une carte est pointée sur la map
     * @param x     Coordonnées x de la souris
     * @param y     Coordonnée y de la souris
     * @return      L'id de la carte pointée, -1 si aucune carte n'est pointée
     */
    public int estPointéSurCarte(int x, int y) {
        int resultat=-1;
        if (!déplacement){
            for (int i=0;i<nbStart;i++) {
                if (resultat==-1) {
                    if (this.x[i]!=xStart && this.y[i]!=yStart && x>=this.x[i] && x<=this.x[i]+40 && y>=this.y[i] && y<=this.y[i]+40) {
                        resultat=i;
                    }
                }
            }
        }
        return resultat;
    }

    /**
     * Change le statut de la carte pour : En déplacement
     */
    public void debutDéplacement() {
        déplacement=true;
        nb--;
    }

    /**
     * Permet de reprendre le déplacement d'une carte déjà placée sur la map
     * @param idCarte   L'index de la carte reprise en main
     */
    public void reprendreDéplacement(int idCarte) {
        déplacement=true;
        index=idCarte;
    }
        
    /**
     * Vérifie si la carte est en cours de déplacement
     * @return  Vrai si la carte est en déplacement
     */
    public boolean estEnDéplacement() {
        return déplacement;
    }
    
    /**
     * Déplace la carte aux nouvelles coordonnées x,y et vérifie si la case pointée est acceptable (vide) ou non
     * @param x     Nouvelles coordonnée X de la carte
     * @param y     Nouvelle coordonnée Y de la carte
     * @param act   L'action de la case sous ces coordonnées
     */
    public void déplacer(int x, int y, Actions act) {
        this.x[index]=x-20;
        this.y[index]=y-20;
        if (act==Actions.Rien) déplacementAutorisé=true;
        else                   déplacementAutorisé=false;
    }
    
    /**
     * Place la carte dans son nouvel emplacement si le déplacement est autorisé, 
     * sinon la remet dans son emplacement d'origine
     * @param x     La nouvelle coordonnée x de la carte
     * @param y     La nouvelle coordonnée y de la carte
     * @param act   L'action de la case dans ces coordonnées x,y
     * @return      Vrai si le placement a été effectué, Faux si il a été refusé.
     */
    public boolean placer(int x, int y, Actions act) {
        if (act==Actions.Rien) {
            déplacement=false;
            this.x[index]=cases.debutCaseX(x);
            this.y[index]=cases.debutCaseY(y);
            indexPlacés[index]=true;
            index=prochainsIndexNonAffecté();
            return true;
        } else {
            this.x[index]=xStart;
            this.y[index]=yStart;
            déplacement=false;
            nb++;    
            indexPlacés[index]=false;
            index=prochainsIndexNonAffecté();
            return false;
        }
    }
    

    
    /**
     * Indique si la carte et plus précisément son index 'id' doit être surligné
     * @param surligner     True si on doit surligner, false sinon
     * @param id            Index de la carte à surligner
     */
    public void surligner(boolean surligner, int id) {
        this.surlignage=id;
    }
    
    /**
     * @see #surligner(boolean, int) 
     * @param surlignage    True si la carte doit être surligné, faux sinon
     */
    public void surligner(boolean surlignage) {
        surligner(surlignage, -1);
    }
    
    
    /**
     * Retourne l'action de la carte
     * @return action de la carte
     */
    public Actions get_action() {
        return carte;
    }
    
    /**
     * Remet la carte à son emplacement d'origine, et annule le déplacement en cours.
     */
    public void reset() {
          for (int i=0; i<nbStart;i++) {
            x[i]=xStart;
            y[i]=yStart;
          }
          déplacement=déplacementAutorisé=false;
          surlignage=-1;
          nb=nbStart;
          index=0;
          Arrays.fill(indexPlacés, false);
    }
    
    /**
     * Retourne le prochain index non affecté ( = non placé )
     * @return  Prochain index à false, sinon -1;
     */
     private int prochainsIndexNonAffecté() {
         for (int i=0; i<nbStart;i++) {
             if (!indexPlacés[i]) return i;
         }
         return -1;
     }
     
     /**
      * Indique le nombre d'index affectés
      * @return Nb d'index affectés
      */
     private int nbIndexAffectés() {
         int i=0;
         for (boolean b:indexPlacés) if (b) i++;
         return i;
     }
    
    
    /**
     * Disposition des différentes actions dans le sprite dédié 
     * @throws org.newdawn.slick.SlickException
     */
    public static void relations() throws SlickException {
        RelationCarteTile.put(Actions.DirectionD,            new cases(1,1));
        RelationCarteTile.put(Actions.DirectionB,            new cases(2,1));
        RelationCarteTile.put(Actions.DirectionG,            new cases(3,1));
        RelationCarteTile.put(Actions.DirectionH,            new cases(4,1));
        
        RelationCarteTile.put(Actions.Tir,                   new cases(1,2));
        RelationCarteTile.put(Actions.Bouclier,              new cases(2,2));
        RelationCarteTile.put(Actions.Tir4,                  new cases(3,2));

        RelationCarteTile.put(Actions.DirectionDB,            new cases(1,3));
        RelationCarteTile.put(Actions.DirectionBG,            new cases(2,3));
        RelationCarteTile.put(Actions.DirectionGH,            new cases(3,3));
        RelationCarteTile.put(Actions.DirectionHD,            new cases(4,3));
        
        spriteCartes=new SpriteSheet("res/sprite_cartes.png", 40, 40);
    }
    
    /**
     * Remet à 0 le parcours de 8 cases disponibles d'origine.
     */
    public static void réinit() {
        ligEnCours=1;
        colEnCours=1;
    }
            
}